package project_part2;

import java.util.Vector;

public class ContactList extends Vector<Contact> {
	private static final long serialVersionUID = 1L;

	private int findCursor = 0;//starting point for find
	
	public Contact addContact(String firstName, String middleName, String lastName, String dob) throws IllegalArgumentException {
		Contact newContact = new Contact(firstName, middleName, lastName, dob);
		this.add(newContact);
		return newContact;
	}
	
	public Contact findContact(String criteria, int fieldType) throws IllegalArgumentException {
		findCursor = 0;
		return findNextContact(criteria, fieldType);
	}
	
	public Contact findNextContact(String criteria, int fieldType) throws IllegalArgumentException {
		for(int i = findCursor; i < this.size(); i++) {
			Contact contact = (Contact) this.get(i);
			switch(fieldType) {
				case Contact.FIELD_FIRSTNAME :
					if(contact.getFirstName().contains(criteria)) {
						findCursor = i + 1;
						return contact;
					}
					break;
				case Contact.FIELD_LASTNAME :
					if(contact.getLastName().contains(criteria)) {
						findCursor = i + 1;
						return contact;
					}
					break;
				case Contact.FIELD_MIDDLENAME :
					if(criteria == null) {
						if(contact.getMiddleName() == null) {
							findCursor = i + 1;
							return contact;
						} else
							break;
					}
					if(contact.getMiddleName() == null)
						break;
					if(criteria.length() == 0) {
						if(contact.getMiddleName().length() == 0) {
							findCursor = i + 1;
							return contact;
						} else
							break;
					}
					if(contact.getMiddleName().contains(criteria)) {
						findCursor = i + 1;
						return contact;
					}
					break;
				case Contact.FIELD_DOB :
					Contact testContact = null;
					try {
						testContact = new Contact("a", "", "b", criteria);
					} catch(Exception e) {
						throw new IllegalArgumentException("DOB should be string in format of mm/dd/yyyy !");
					}
					if(contact.getFormattedDOB().equalsIgnoreCase(testContact.getFormattedDOB())) {
						findCursor = i + 1;
						return contact;
					}
					break;
			}
		}
		findCursor = 0;//reset find cursor
		return null;
	}
	
	public Contact [] findMatches(Contact c1, MatchCriteria crit, int threshold) {
		//return a list of contacts that match c1 according to criteria within specified threshold
		//the greater the threshold, the more stringent the matching
		if(c1 == null)
			throw new IllegalArgumentException("Must provide a valid contact");
		if(crit == null)
			throw new IllegalArgumentException("Must provide valid MatchCriteria");
		if(threshold < 1 || threshold > 4)
			throw new IllegalArgumentException("Threshold must be between 1 and 4");
		if(!crit.matchAge && !crit.matchGender && !crit.matchHeight && !crit.matchWeight)
			throw new IllegalArgumentException("Must have at least one active criterion");
		if(crit.matchAge) {
			//valid age range is between 0 and 200
			if(crit.ageLow < 0 || crit.ageHigh < 0 || crit.ageLow > 200 || crit.ageHigh > 200)
				throw new IllegalArgumentException("Age criterion range is between 0 and 200");
			if(crit.ageLow > crit.ageHigh)
				throw new IllegalArgumentException("Age criterion high value must be >= than low value");
		}
		if(crit.matchWeight) {
			//valid weight range is between 0 and 2000
			if(crit.weightLow < 0 || crit.weightHigh < 0 || crit.weightLow > 2000 || crit.weightHigh > 2000)
				throw new IllegalArgumentException("Weight criterion range is between 0 and 2000");
			if(crit.weightLow > crit.weightHigh)
				throw new IllegalArgumentException("Weight criterion high value must be >= than low value");
		}
		if(crit.matchHeight) {
			if(crit.heightHigh == null || crit.heightLow == null)
				throw new IllegalArgumentException("Height criterion must have valid low and high values");
			if(crit.heightHigh.isShorterThan(crit.heightLow))
				throw new IllegalArgumentException("Height criterion high value must be >= than low value");
		}
		if(crit.matchGender) {
			if(crit.getGenders() == null)
				throw new IllegalArgumentException("Gender criterion must have at least 1 valid gender added");
			if(crit.getGenders().size() < 1)
				throw new IllegalArgumentException("Gender criterion must have at least 1 valid gender added");
		}
		Vector<Contact> matches = new Vector<Contact>();
		for(int i = 0; i < this.size(); i++) {
			Contact contact = (Contact) this.get(i);
			if(contact.equals(c1))
				continue;
			int score = 0;
			if(crit.matchAge) {
				if(contact.getAge() >= crit.ageLow && contact.getAge() <= crit.ageHigh)
					score++;
			}
			if(crit.matchWeight) {
				if(contact.getWeight() >= crit.weightLow && contact.getWeight() <= crit.weightHigh)
					score++;
			}
			if(crit.matchGender) {
				for(int j = 0; j < (crit.getGenders().size()-1); j++) {
					Gender gender = (Gender) crit.getGenders().get(j);
					if(contact.getGender() == gender)
						score++;
				}
			}
			if(crit.matchHeight) {
				if(contact.getHeight().isTallerOrEqualThan(crit.heightLow) && contact.getHeight().isShorterOrEqualThan(crit.heightHigh))
					score++;
			}
			if(score >= threshold)
				matches.add(contact);
		}
		Contact[] ret = new Contact[matches.size()];
		System.out.println(matches);
		matches.toArray(ret);
		return ret;
	}
	
	public String toString() {
		String ret = "Contact List contents:\n";
		if(this.size() > 0) {
			for(Contact contact : this) 
				ret += contact.toString() + "\n";
		} else
			ret += "no contacts\n";
		return ret;
	}

}
